use std::{borrow::Cow, error::Error, string};
use crossbeam::channel::Receiver;
use log::{debug, info};
use serde::{Deserialize, Serialize};

use crate::{encoding::Coding, server::{Response, StatementResult}, sql::{parser::Token, DataType, Table, Value}, CustomError};
use super::{bitcash::BitCash, statement, Entry, Insert, SendMessage, Statement, Update};

pub trait Engine {
    fn persistent(&mut self, key: &Vec<u8>, value: &Vec<u8>) -> Result<(), Box<dyn Error>>;
    fn execute(&mut self) -> Result<(), Box<dyn Error>>;
}

pub struct BitCashEngine {
    pub bitcash: BitCash,
    pub recevier: Receiver<SendMessage>,
}

impl BitCashEngine {
    pub fn new(bitcash: BitCash, recevier: Receiver<SendMessage>) -> Self {
        BitCashEngine { 
            bitcash,
            recevier,
        }
    }

    pub fn prepared_statement(&self, token: Token) -> Result<Statement, Box<dyn Error>> {
        match token {
            Token::Create(table) => {
                if let Some(_)  = self.get_table(&table.table_name)? {
                    return Err(CustomError::ExecuteError(format!("[{}] is exist", table.table_name)).into())
                }
                
                Ok(Statement::Create(table))
            },
            Token::Select(select) => {
                let table_option  = self.get_table(&select.table_name)?;
                let table = match table_option {
                    Some(table) => table,
                    None => return Err(CustomError::ExecuteError(format!("[{}] is not exist", select.table_name)).into())
                };

                Ok(Statement::Select(select))
            },
            Token::Insert(insert) => {
                let table_option  = self.get_table(&insert.table_name)?;
                let table = match table_option {
                    Some(table) => table,
                    None => return Err(CustomError::ExecuteError(format!("[{}] is not exist", insert.table_name)).into())
                };
                
                let mut rows = Vec::new();
                match insert.literals {
                    Some(literals) => {
                        for vals in &insert.val {
                            let mut values = Vec::new();
                            for column in &table.columns {
                                if let Some(pos) = literals.iter().position(|name| name == &column.name) {
                                    let val = vals.get(pos).ok_or(CustomError::IndexOutOfBounds)?;
                                    let value = Self::parse_value(val, &column.data_type)?;
                                    let entry = statement::Entry {
                                        key: column.name.clone(),
                                        value: value,
                                    };
                                    values.push(entry);

                                } else {
                                    let entry = statement::Entry {
                                        key: column.name.clone(),
                                        value: column.default.clone().unwrap(),
                                    };
                                    values.push(entry);
                                }
                            }
                            rows.push(values);
                        }
                    },
                    None => {
                        for vals in &insert.val {
                            let mut values = Vec::new();
                            for (index, column) in table.columns.iter().enumerate() {
                                let val = vals.get(index).ok_or(CustomError::IndexOutOfBounds)?;
                                let value = Self::parse_value(val, &column.data_type)?;
                                let entry = statement::Entry {
                                    key: column.name.clone(),
                                    value: value,
                                };
                                values.push(entry);
                            }
                            rows.push(values);
                        }
                    },
                };
                let statement_insert = Insert {
                    table_name: insert.table_name,
                    primary_key: table.primary_key,
                    values: rows,
                };
                Ok(Statement::Insert(statement_insert))
            },
            Token::Update(update) => {
                let table_option  = self.get_table(&update.table_name)?;
                let table = match table_option {
                    Some(table) => table,
                    None => return Err(CustomError::ExecuteError(format!("[{}] is not exist", update.table_name)).into())
                };

                let mut columns = Vec::new();
                for column in update.columns {
                    if let Some(pos) = table.columns.iter().position(|col| &col.name == &column.key) {
                        let entry = statement::Entry {
                            key: column.key,
                            value: Self::parse_value(&column.val, &table.columns.get(pos).unwrap().data_type)?,
                        };
                        columns.push(entry);
                        
                    }
                }
                
                let mut primary_key = None;
                let mut uwhere_cols = None;
                if let Some(uwhere) = update.uwhere {
                    let mut uwhere_columns = Vec::new();
                    for (index, column) in uwhere.iter().enumerate() {
                        if let Some(pos) = table.columns.iter().position(|col| &col.name == &column.key) {
                            if pos == table.primary_key {
                                primary_key = Some(index);
                            }
                            let entry = statement::Entry {
                                key: column.key.clone(),
                                value: Self::parse_value(&column.val, &table.columns.get(pos).unwrap().data_type)?,
                            };
                            uwhere_columns.push(entry);
                        }
                    }
                    uwhere_cols = Some(uwhere_columns);
                }

                let statement_update = Update {
                    table_name: update.table_name,
                    primary_key,
                    columns,
                    uwhere: uwhere_cols,
                };
                Ok(Statement::Update(statement_update))
            },
            Token::Alter => {
                Ok(Statement::Alter)
            },
            Token::Delete => {
                Ok(Statement::Delete)
            },
        }
    }

    pub fn get_table(&self, table_name: &str) -> Result<Option<Table>, Box<dyn Error>> {
        let key = bincode::serialize(&Key::Key(Cow::Borrowed(table_name)))?;
        if let Ok((_, Some(value))) = self.bitcash.read(&key) {
            let table = Table::decoding(&value)?;
            return Ok(Some(table));
        }
        Ok(None)
    }

    // 将字符串解析为对应数据类型的值
    fn parse_value(val: &str, data_type: &DataType) -> Result<Value, CustomError> {
        match data_type {
            DataType::Bool => val.parse::<bool>()
                .map(Value::Bool)
                .map_err(|_| CustomError::ParseError(format!("Failed to parse '{}' as bool", val))),
            DataType::Float => val.parse::<f64>()
                .map(Value::Float)
                .map_err(|_| CustomError::ParseError(format!("Failed to parse '{}' as float", val))),
            DataType::Int => val.parse::<i64>()
                .map(Value::Int)
                .map_err(|_| CustomError::ParseError(format!("Failed to parse '{}' as int", val))),
            DataType::Text => Ok(Value::Text(val.to_string())),
            DataType::TimeStamp => val.parse::<i64>()
                .map(Value::TimeStamp)
                .map_err(|_| CustomError::ParseError(format!("Failed to parse '{}' as timestamp", val))),
        }
    }
}

impl Engine for BitCashEngine {
    fn persistent(&mut self, key: &Vec<u8>, value: &Vec<u8>) -> Result<(), Box<dyn Error>> {
        self.bitcash.write(key, value)?;
        Ok(())
    }

    fn execute(&mut self) -> Result<(), Box<dyn Error>> {
        loop {
            if let Ok(message) = self.recevier.recv() {
                match message {
                    SendMessage::Request(token, sender) => {
                        let statement = self.prepared_statement(token);
                        match statement {
                            Ok(statement::Statement::Create(table)) => {
                                let key = Key::Key(Cow::Borrowed(&table.table_name)).encoding()?;
                                let value = table.encoding()?;
                                self.persistent(&key, &value)?;
                                let response = Response::Execute(StatementResult::CreateTable { name: table.table_name });
                                sender.send(response)?;
                            },
                            Ok(statement::Statement::Insert(insert)) => {
                                let table_name = insert.table_name;
                                let primary_key = insert.primary_key;
                                for vals in &insert.values {
                                    let primary_key_value = vals.get(primary_key).unwrap();
                                    let key_value: String = primary_key_value.into();
                                    let key = Key::Row(Cow::Borrowed(&table_name), Cow::Borrowed(&key_value)).encoding()?;
                                    let value = vals.encoding()?;
                                    self.persistent(&key, &value)?;
                                }
                                
                                let response = Response::Execute(StatementResult::Insert { count: insert.values.len() as u64 });
                                sender.send(response)?;
                            },
                            Ok(statement::Statement::Select(select)) => {
                                let table_name = select.table_name;
                                let key = Key::Row(Cow::Borrowed(&table_name), Cow::Borrowed("1")).encoding()?;
                                match self.bitcash.read(&key) {
                                    Ok((_, Some(bytes))) => {
                                        let values = bincode::deserialize::<Vec<Entry>>(&bytes)?;
                                        let response = Response::Execute(StatementResult::Select {rows: values });
                                        sender.send(response)?;
                                    },
                                    Ok((_, None)) => {
                                        let response = Response::Execute(StatementResult::Select {rows: Vec::new() });
                                        sender.send(response)?;
                                    }
                                    Err(_) => {}, 
                                }
                            },
                            Ok(statement::Statement::Update(update)) => {},
                            Ok(statement::Statement::Alter) => {},
                            Ok(statement::Statement::Delete) => {},
                            Err(e) => {
                                let response = Response::Err(0, e.to_string());
                                sender.send(response)?;
                            },
                        }
                    },
                    _ => return Err(CustomError::ExecuteError("".to_string()).into()),
                }
            }
        }
        Ok(())
    }
}

// #[derive(Debug, Serialize, Deserialize)]
// struct Entry {
//     pub index: u64,
//     pub data: Vec<u8>,
// }

// impl Entry {
//     pub fn new(index: u64, data: Vec<u8>) -> Self {
//         Entry { index, data }
//     }
// }

#[derive(Debug, Serialize, Deserialize)]
pub enum Key<'a> {
    Key(Cow<'a, str>),
    Index(Cow<'a, str>),
    Row(Cow<'a, str>, Cow<'a, str>),
}